package com.ext.aic.box.wx.chat;

import android.accessibilityservice.GestureDescription;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityNodeInfo;

import com.ext.aic.AICApplication;
import com.ext.aic.apis.chat.AgentReplySyncRequest;
import com.ext.aic.beans.AgentReplySyncResult;
import com.ext.aic.beans.box.ChatWindowElement;
import com.ext.aic.beans.box.NotificationMessage;
import com.ext.aic.beans.box.ReceiveMessage;
import com.ext.aic.beans.params.AgentReplyParams;
import com.ext.aic.beans.response.AgentReplyResponse;
import com.ext.aic.box.PositionManager;
import com.ext.aic.box.WindowManager;
import com.ext.aic.box.logs.WxReplyRequestLogsManager;
import com.ext.aic.box.model.ClientUIConstants;
import com.ext.aic.box.model.PositionMeta;
import com.ext.aic.box.wx.conversation.ConversationManager;
import com.ext.aic.box.wx.reply.ReplyManager;
import com.ext.aic.enums.ChatSource;
import com.ext.aic.events.OnAccessibilityServiceEvent;
import com.ext.aic.events.OnSoftKeyboardListener;
import com.ext.aic.handler.AccessibilityClickHandler;
import com.ext.aic.utils.BoxUtils;
import com.ext.aic.utils.UserUtils;
import com.eyinfo.android_pure_utils.HandlerManager;
import com.eyinfo.android_pure_utils.events.Action0;
import com.eyinfo.android_pure_utils.events.Action1;
import com.eyinfo.android_pure_utils.events.RunnableParamsN;
import com.eyinfo.android_pure_utils.utils.ObjectJudge;
import com.eyinfo.android_pure_utils.utils.PixelUtils;

import java.util.List;
import java.util.Objects;

import lombok.Getter;
import lombok.Setter;

public class ChatManager extends WindowManager {
    //用户聊天属性是否待赋值
    @Getter
    private boolean isTobeAssignedWithChat = false;
    @Getter
    private boolean chatting = false;
    private ChatWindowElement chatWindowElement;
    private AccessibilityNodeInfo windowNode;
    private ChatSource source;
    @Setter
    private NotificationMessage notificationMessage;
    private ReceiveMessage receiveMessage = new ReceiveMessage();
    private AccessibilityNodeInfo editNode;

    //region 参数
    public void setParams(boolean isTobeAssignedWithChat, ChatSource source) {
        this.isTobeAssignedWithChat = isTobeAssignedWithChat;
        this.source = source;
    }
    //endregion

    //region step0 初始化聊天窗口
    public void initChat(ChatWindowElement chatWindowElement) {
        super.onCreate();
        this.chatWindowElement = chatWindowElement;
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        chatting = true;
        isTobeAssignedWithChat = false;
        windowNode = getWindowNode();

        WxReplyRequestLogsManager.getInstance().setEnterChatWindow(true);

        if (source == ChatSource.SEARCH) {
            ReplyManager replyManager = serviceEvent.getReplyManager();
            AgentReplyParams currentReplyParams = replyManager.getCurrentReplyParams();
            AgentReplyResponse currentReplyResponse = replyManager.getCurrentReplyResponse();
            receiveMessage.setUser(currentReplyParams.getUsername());
            receiveMessage.setSessionId(currentReplyParams.getSessionId());
            receiveMessage.setMessage(currentReplyResponse.getContent());
            triggerEditSoftKeyboard();
        } else if (source == ChatSource.CONVERSATION) {
            receiveMessage.setUser(notificationMessage.getUser());
            receiveMessage.setSessionId(notificationMessage.getSessionId());
            receiveMessage.setMessage(notificationMessage.getMessage());
            requestReplyForConversation();
        }
    }
    //endregion

    //region step1 以模拟点击方式触发编辑框软键盘，以便后面粘贴;因为这个窗口通过find查找的AccessibilityNodeInfo无效

    private void triggerEditSoftKeyboard() {
        Context applicationContext = AICApplication.getInstance().getApplicationContext();
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        ClientUIConstants clientUIConstants = serviceEvent.getClientUIConstants();

        Rect winRect = new Rect();
        windowNode.getBoundsInScreen(winRect);

        PositionMeta meta = PositionManager.getInstance().getChatEditPosition(clientUIConstants, winRect);
        editClickHandler.clickAtPoint(serviceEvent.getService(), meta.getX(), meta.getY());
    }

    AccessibilityClickHandler editClickHandler = new AccessibilityClickHandler() {
        //step2 通过剪贴板的方式粘贴消息，因为这个窗口通过find查找的AccessibilityNodeInfo直接输入无效
        @Override
        protected void onTriggerClickSuccess(GestureDescription gesture) {
            awaitShowSoftKeyboard(new OnSoftKeyboardListener() {
                @Override
                public void onSoftKeyboardShow(int height) {
                    pasteText();
                }
            });
        }
    };

    private void showPasteMenus(int softKeyboardHeight) {
        Context applicationContext = AICApplication.getInstance().getApplicationContext();
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        ClientUIConstants clientUIConstants = serviceEvent.getClientUIConstants();

        Rect editRect = new Rect();
        editNode.getBoundsInScreen(editRect);

        PositionMeta meta = PositionManager.getInstance().getChatPasteMenusPositionForEdit(clientUIConstants, softKeyboardHeight, editRect);
        againClickEditHandler.clickAtPoint(serviceEvent.getService(), meta.getX(), meta.getY(), 1200);
    }

    private AccessibilityClickHandler againClickEditHandler = new AccessibilityClickHandler() {
        @Override
        protected void onTriggerClickSuccess(GestureDescription gesture) {
            OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
            clickEditPasteArea(serviceEvent.getSoftKeyboardHeight());
        }
    };

    private void pasteText() {
        editNode = findEditViewByTraversal();
        if (editNode == null) {
            finish();
            return;
        }
        //粘贴之前清空原文本内容
        clearText(editNode);
        //粘贴文本至剪贴板
        assignEditText(editNode, receiveMessage.getMessage(), new Action1<Boolean>() {
            @Override
            public void call(Boolean hasPrimaryClip) {
                OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
                showPasteMenus(serviceEvent.getSoftKeyboardHeight());
            }
        });
    }

    private void clearText(AccessibilityNodeInfo editNode) {
        Bundle args = new Bundle();
        args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "");
        editNode.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
    }

    private void delayPasteText() {
        HandlerManager.getInstance().postDelayed(new RunnableParamsN<Object>() {
            @Override
            public void run(Object... objects) {
                windowNode = getWindowNode();
                pasteText();
            }
        }, 100);
    }
    //endregion

    //region step3 这里只能通过点击软键盘粘贴区域，这里通过代码方式无法显示粘贴图标
    private void clickEditPasteArea(int softKeyboardHeight) {
        Context applicationContext = AICApplication.getInstance().getApplicationContext();
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        ClientUIConstants clientUIConstants = serviceEvent.getClientUIConstants();

        Rect editRect = new Rect();
        editNode.getBoundsInScreen(editRect);

        PositionMeta meta = PositionManager.getInstance().getChatEditPasteArea(clientUIConstants, softKeyboardHeight, editRect);
        clickEditPasteAreaHandler.clickAtPoint(serviceEvent.getService(), meta.getX(), meta.getY(), 500);
    }

    private AccessibilityClickHandler clickEditPasteAreaHandler = new AccessibilityClickHandler() {
        @Override
        protected void onTriggerClickSuccess(GestureDescription gesture) {
            awaitHideSoftKeyboardFinish(new Action0() {
                @Override
                public void call() {
                    send();
                }
            });
        }
    };
    //endregion

    //region step4 通过模拟点击方式发送消息
    private void send() {
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();

        ClientUIConstants clientUIConstants = serviceEvent.getClientUIConstants();

        Rect winRect = new Rect();
        windowNode.getBoundsInScreen(winRect);

        PositionMeta meta = PositionManager.getInstance().getChatSendPosition(clientUIConstants, winRect);
        sendClickHandler.clickAtPoint(serviceEvent.getService(), meta.getX(), meta.getY());
    }

    private void finish() {
        closeChatWindow();

        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();

        ConversationManager conversationManager = serviceEvent.getConversationManager();
        conversationManager.setMatchedMessage(false);
    }

    private AccessibilityClickHandler sendClickHandler = new AccessibilityClickHandler() {
        @Override
        protected void onTriggerClickSuccess(GestureDescription gesture) {
            finish();
        }
    };
    //endregion

    //region step5 关闭聊天窗口
    private void closeChatWindow() {
        Context applicationContext = AICApplication.getInstance().getApplicationContext();
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        ClientUIConstants clientUIConstants = serviceEvent.getClientUIConstants();
        int statusHeight = clientUIConstants.getStatusHeight();
        int headerHeight = clientUIConstants.getHeaderHeight();

        int backWidth = PixelUtils.dip2px(applicationContext, 30);

        float x = backWidth / 2f;
        float y = statusHeight + headerHeight / 2f;
        AccessibilityClickHandler clickHandler = new AccessibilityClickHandler();
        clickHandler.clickAtPoint(serviceEvent.getService(), x, y);
    }
    //endregion

    //region 各个节点获取
    private AccessibilityNodeInfo findEditViewByTraversal() {
        AccessibilityNodeInfo windowNode = getWindowNode();
        List<AccessibilityNodeInfo> nodes = windowNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/bkk");
        if (!ObjectJudge.isNullOrEmpty(nodes)) {
            return nodes.get(0);
        }
        List<AccessibilityNodeInfo> parentNodes = windowNode.findAccessibilityNodeInfosByViewId(chatWindowElement.getEditViewId());
        if (ObjectJudge.isNullOrEmpty(parentNodes)) {
            parentNodes = windowNode.findAccessibilityNodeInfosByViewId("com.tencent.mm:id/k52");
        }
        if (ObjectJudge.isNullOrEmpty(parentNodes)) {
            return findEditViewByTraversal();
        }
        AccessibilityNodeInfo nodeInfo = parentNodes.get(0);
        return findEditNextTraversal(nodeInfo);
    }

    private AccessibilityNodeInfo findEditNextTraversal(AccessibilityNodeInfo nodeInfo) {
        int childCount = nodeInfo.getChildCount();
        if (childCount > 0) {
            for (int i = 0; i < childCount; i++) {
                AccessibilityNodeInfo child = nodeInfo.getChild(i);
                int count = child.getChildCount();
                if (count > 0) {
                    return findEditNextTraversal(child);
                } else {
                    String className = Objects.toString(child.getClassName(), "");
                    if (TextUtils.equals(className, "android.widget.EditText")) {
                        return child;
                    }
                }
            }
        } else {
            String className = Objects.toString(nodeInfo.getClassName(), "");
            if (TextUtils.equals(className, "android.widget.EditText")) {
                return nodeInfo;
            }
        }
        return null;
    }

    private AccessibilityNodeInfo getWindowNode() {
        OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
        AccessibilityNodeInfo rootNode = serviceEvent.getRootNode();
        List<AccessibilityNodeInfo> nodes = rootNode.findAccessibilityNodeInfosByViewId(chatWindowElement.getWindowId());
        if (ObjectJudge.isNullOrEmpty(nodes)) {
            return rootNode;
        }
        return nodes.get(0);
    }

    private AccessibilityNodeInfo getListNode(AccessibilityNodeInfo windowNode) {
        List<AccessibilityNodeInfo> nodes = windowNode.findAccessibilityNodeInfosByViewId(chatWindowElement.getChatListViewId());
        if (ObjectJudge.isNullOrEmpty(nodes)) {
            return windowNode;
        }
        return nodes.get(0);
    }
    //endregion

    //region 消息处理
    private String getLastMessage(AccessibilityNodeInfo windowNode) {
        AccessibilityNodeInfo listNode = getListNode(windowNode);
        int childCount = listNode.getChildCount();
        if (childCount == 0) {
            return "";
        }
        AccessibilityNodeInfo lastNode = listNode.getChild(childCount - 1);
        int count = lastNode.getChildCount();
        if (count == 0) {
            return "";
        }
        AccessibilityNodeInfo textNode = lastNode.getChild(count - 1);
        if (textNode == null) {
            return "";
        }
        return Objects.toString(textNode.getText(), "");
    }
    //endregion

    //region 请求AI回复发送消息
    public void requestReplyForConversation() {
        AgentReplyParams replyParams = new AgentReplyParams();
        replyParams.setUserId(UserUtils.getInstance().getUserId());
        replyParams.setSessionId(receiveMessage.getSessionId());
        replyParams.setUsername(receiveMessage.getUser());
        replyParams.setMessage(receiveMessage.getMessage());

        AgentReplySyncRequest replySyncRequest = new AgentReplySyncRequest() {
            @Override
            protected void onAgentReplySyncSuccess(AgentReplySyncResult response, AgentReplyResponse replyResponse) {
                OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
                ConversationManager conversationManager = serviceEvent.getConversationManager();
                if (TextUtils.isEmpty(response.getContent())) {
                    closeChatWindow();
                    conversationManager.setMatchedMessage(false);
                    printLog(replyParams, replyResponse, null, 1);
                    return;
                }
                printLog(replyParams, replyResponse, null, 0);
                receiveMessage.setMessage(response.getContent());
                triggerEditSoftKeyboard();
                conversationManager.setMatchedMessage(false);
            }
        };
        replySyncRequest.request(replyParams);
    }
    //endregion
}
